function GeoServer(url, user, password) {
    this._url = url;
    this._token = 'Basic ' + btoa(`${user}:${password}`);
}

/**
 * 获取工作空间
 * @returns 
 */
GeoServer.prototype.getWorkspaces = function () {
    let that = this;
    return new Promise(function (resolve, reject) {
        $.ajax({
            url: `${that._url}/rest/workspaces`,
            method: 'GET',
            beforeSend: request => {
                request.setRequestHeader('Authorization', that._token);
            },
            success: response => {
                resolve(response);
            },
            error: error => {
                reject(error);
            }
        })
    })

}

/**
 * 添加工作空间
 * @param {String} name 工作空间名称
 * @returns 
 */
GeoServer.prototype.createWorkspace = function (name) {
    let that = this;
    return new Promise(function (resolve, reject) {
        let data = {
            workspace: {
                name: name
            }
        }
        $.ajax({
            url: `${that._url}/rest/workspaces`,
            method: 'POST',
            dataType: 'text',
            data: JSON.stringify(data),
            beforeSend: request => {
                request.setRequestHeader('Authorization', that._token);
            },
            success: response => {
                resolve(response);
            },
            error: error => {
                reject(error);
            }
        })
    })
}

/**
 * 获取某工作空间内所有的数据存储
 * @param {String} workspace 工作空间
 * @returns 
 */
GeoServer.prototype.getDatastores = function (workspace) {
    let that = this;
    return new Promise(function (resolve, reject) {
        $.ajax({
            url: `${that._url}/rest/workspaces/${workspace}/datastores`,
            method: 'GET',
            beforeSend: request => {
                request.setRequestHeader('Authorization', that._token);
            },
            success: response => {
                resolve(response);
            },
            error: error => {
                reject(error);
            }
        })
    });
}

/**
 * 获取数据存储详细信息
 * @param {String} workspace 工作空间
 * @param {String} store 数据存储名称
 * @returns 
 */
GeoServer.prototype.getDatastoreInfo = function (workspace, store) {
    let that = this;
    return new Promise(function (resolve, reject) {
        $.ajax({
            url: `${that._url}/rest/workspaces/${workspace}/datastores/${store}`,
            method: 'GET',
            beforeSend: request => {
                request.setRequestHeader('Authorization', that._token);
            },
            success: response => {
                resolve(response);
            },
            error: error => {
                reject(error);
            }
        })
    });
}

/**
 * 创建POSTGIS数据存储
 * @param {String} workspace 工作空间
 * @param {String} store 数据存储名称
 * @param {String} host PG主机
 * @param {Number} port PG端口号
 * @param {String} database PG数据库
 * @param {String} user PG用户名
 * @param {String} password PG密码
 */
GeoServer.prototype.createPGDatastore = function (workspace, store, host, port, database, user, password) {
    let that = this;
    return new Promise(function (resolve, reject) {
        let data = {
            dataStore: {
                name: store,
                connectionParameters:
                {
                    entry: [
                        {
                            "@key": "host",
                            "$": host
                        },
                        {
                            "@key": "port",
                            "$": port
                        },
                        {
                            "@key": "database",
                            "$": database
                        },
                        {
                            "@key": "user",
                            "$": user
                        },
                        {
                            "@key": "passwd",
                            "$": password
                        },
                        {
                            "@key": "dbtype",
                            "$": "postgis"
                        },
                        {
                            "@key": "schema",
                            "$": "public"
                        },
                        {
                            "@key": "Evictor run periodicity",
                            "$": "300"
                        },
                        {
                            "@key": "Max open prepared statements",
                            "$": "50"
                        },
                        {
                            "@key": "encode functions",
                            "$": "true"
                        },
                        {
                            "@key": "Batch insert size",
                            "$": "1"
                        },
                        {
                            "@key": "preparedStatements",
                            "$": "false"
                        },
                        {
                            "@key": "Loose bbox",
                            "$": "true"
                        },
                        {
                            "@key": "SSL mode",
                            "$": "DISABLE"
                        },
                        {
                            "@key": "Estimated extends",
                            "$": "true"
                        },
                        {
                            "@key": "fetch size",
                            "$": "1000"
                        },
                        {
                            "@key": "Expose primary keys",
                            "$": "false"
                        },
                        {
                            "@key": "Support on the fly geometry simplification",
                            "$": "true"
                        },
                        {
                            "@key": "Connection timeout",
                            "$": "20"
                        },
                        {
                            "@key": "create database",
                            "$": "false"
                        },
                        {
                            "@key": "Method used to simplify geometries",
                            "$": "FAST"
                        },
                        {
                            "@key": "min connections",
                            "$": "1"
                        },
                        {
                            "@key": "max connections",
                            "$": "10"
                        },
                        {
                            "@key": "Evictor tests per run",
                            "$": "3"
                        },
                        {
                            "@key": "Test while idle",
                            "$": "true"
                        },
                        {
                            "@key": "Max connection idle time",
                            "$": "300"
                        }
                    ]
                }
            }
        }
        $.ajax({
            url: `${that._url}/rest/workspaces/${workspace}/datastores`,
            method: 'POST',
            dataType: 'text',
            data: JSON.stringify(data),
            beforeSend: request => {
                request.setRequestHeader('Authorization', that._token);
            },
            success: response => {
                resolve(response);
            },
            error: error => {
                reject(error);
            }
        })
    });
}

/**
 * 查看样式是否存在
 * @param {String} workspace 工作空间名称
 * @param {String} name 样式名称
 */
GeoServer.prototype.styleExist = function (workspace, name) {
    let that = this;
    return new Promise(function (resolve, reject) {
        $.ajax({
            url: `${that._url}/rest/workspaces/${workspace}/styles/${name}`,
            method: 'GET',
            beforeSend: request => {
                request.setRequestHeader('Authorization', that._token);
                request.setRequestHeader('Accept', 'application/json');
            },
            success: response => {
                resolve(true);
            },
            error: error => {
                resolve(false);
            }
        })
    });
}

/**
 * 创建样式
 * @param {String} workspace 工作空间名称
 * @param {SLD} sld 样式SLD
 * @returns 
 */
GeoServer.prototype.createStyle = function (workspace, sld) {
    let that = this;
    return new Promise(function (resolve, reject) {
        $.ajax({
            url: `${that._url}/rest/workspaces/${workspace}/styles`,
            method: 'POST',
            dataType: 'text',
            contentType: 'application/vnd.ogc.sld+xml',
            data: sld,
            beforeSend: request => {
                request.setRequestHeader('Authorization', that._token);
            },
            success: response => {
                resolve(response);
            },
            error: error => {
                reject(error);
            }
        })
    });
}

/**
 * 删除样式
 * @param {String} workspace 工作空间名称
 * @param {String} name 样式名称
 */
GeoServer.prototype.deleteStyle = function (workspace, name) {
    let that = this;
    return new Promise(function (resolve, reject) {
        $.ajax({
            url: `${that._url}/rest/workspaces/${workspace}/styles/${name}?purge=true`,
            method: 'DELETE',
            dataType: 'text',
            beforeSend: request => {
                request.setRequestHeader('Authorization', that._token);
            },
            success: response => {
                resolve(true);
            },
            error: error => {
                resolve(false);
            }
        })
    });
}

/**
 * 发布图层
 * @param {String} workspace 工作空间名称
 * @param {String} datastore 数据存储名称
 * @param {String} layername 图层名称
 * @param {Object} meta 数据元数据，包含边界信息、属性字段信息等
 */
GeoServer.prototype.publishLayer = function (workspace, datastore, layername, meta) {
    let that = this;
    return new Promise(function (resolve, reject) {
        //这里必须用XML，JSON没法解析
        let attributes = '';
        meta.attributes.forEach(attribute => {
            attributes += `
            <attribute>
                <name>${attribute.name}</name>
                <minOccurs>0</minOccurs>
                <maxOccurs>1</maxOccurs>
                <nillable>true</nillable>
                <binding>${attribute.binding}</binding>
            </attribute>
            `
        });
        var data = `<?xml version="1.0" encoding="UTF-8"?>
        <featureType>
            <name>${layername}</name>
            <nativeName>${layername}</nativeName>
            <namespace>
                <name>${workspace}</name>
            </namespace>
            <title>${layername}</title>
            <abstract>${layername}图层服务</abstract>
            <keywords>
                <string>${layername}</string>
            </keywords>
            <nativeCRS>EPSG:${meta.srid}</nativeCRS>
            <srs>EPSG:${meta.srid}</srs>
            <nativeBoundingBox>
                <minx>${meta.bounding.minX}</minx>
                <maxx>${meta.bounding.maxX}</maxx>
                <miny>${meta.bounding.minY}</miny>
                <maxy>${meta.bounding.maxY}</maxy>
                <crs>EPSG:${meta.srid}</crs>
            </nativeBoundingBox>
            <latLonBoundingBox>
                <minx>${meta.bounding.minX}</minx>
                <maxx>${meta.bounding.maxX}</maxx>
                <miny>${meta.bounding.minY}</miny>
                <maxy>${meta.bounding.maxY}</maxy>
                <crs>EPSG:${meta.srid}</crs>
            </latLonBoundingBox>
            <projectionPolicy>FORCE_DECLARED</projectionPolicy>
                <enabled>true</enabled>
            <store class="dataStore">
                <name>${workspace}:${datastore}</name>
            </store>
            <maxFeatures>0</maxFeatures>
            <numDecimals>0</numDecimals>
            <overridingServiceSRS>false</overridingServiceSRS>
            <skipNumberMatched>false</skipNumberMatched>
            <circularArcPresent>false</circularArcPresent>
            <attributes>${attributes}</attributes>
        </featureType>
        `

        $.ajax({
            url: `${that._url}/rest/workspaces/${workspace}/featuretypes`,
            method: 'POST',
            dataType: 'text',
            contentType: 'application/xml',
            data: data,
            beforeSend: request => {
                request.setRequestHeader('Authorization', that._token);
            },
            success: response => {
                resolve(response);
            },
            error: error => {
                reject(error);
            }
        });
    });
}

/**
 * 查看图层是否存在
 * @param {String} workspace 工作空间名称
 * @param {String} name 图层名称
 */
GeoServer.prototype.layerExist = function (workspace, name) {
    let that = this;
    return new Promise(function (resolve, reject) {
        $.ajax({
            url: `${that._url}/rest/workspaces/${workspace}/featuretypes/${name}`,
            method: 'GET',
            beforeSend: request => {
                request.setRequestHeader('Authorization', that._token);
                request.setRequestHeader('Accept', 'application/json');
            },
            success: response => {
                resolve(true);
            },
            error: error => {
                resolve(false);
            }
        })
    });
}

/**
* 删除图层
* @param {String} workspace 工作空间名称
* @param {String} name 图层名称
*/
GeoServer.prototype.deleteLayer = function (workspace, name) {
    let that = this;
    return new Promise(function (resolve, reject) {
        $.ajax({
            url: `${that._url}/rest/workspaces/${workspace}/layers/${name}`,
            method: 'DELETE',
            dataType: 'text',
            beforeSend: request => {
                request.setRequestHeader('Authorization', that._token);
            },
            success: response => {
                $.ajax({
                    url: `${that._url}/rest/workspaces/${workspace}/featuretypes/${name}`,
                    method: 'DELETE',
                    dataType: 'text',
                    beforeSend: request => {
                        request.setRequestHeader('Authorization', that._token);
                    },
                    success: response => {
                        resolve(true);
                    },
                    error: error => {
                        resolve(false);
                    }
                })
            },
            error: error => {
                resolve(false);
            }
        });
    });
}

/**
 * 给图层设置样式
 * @param {String} workspace 工作空间名称
 * @param {String} layer 图层名称
 * @param {String} style 样式名称
 */
GeoServer.prototype.setStyle = function (workspace, layer, style) {
    let that = this;
    return new Promise(function (resolve, reject) {
        var data = {
            layer: {
                name: layer,
                defaultStyle: {
                    name: style,
                }
            }
        }

        $.ajax({
            url: `${that._url}/rest/workspaces/${workspace}/layers/${layer}`,
            method: 'PUT',
            dataType: 'text',
            data: JSON.stringify(data),
            beforeSend: request => {
                request.setRequestHeader('Authorization', that._token);
            },
            success: response => {
                resolve(response);
            },
            error: error => {
                reject(error);
            }
        })
    })
}

